
/*
 * Hlpay-Plus aggregate payment system. Copyright
 * (c) 2022-2023 Hlpay Team Copyright has the right of final interpretation.
 */

package com.hlkj.pay.service.admin.impl;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.hlkj.framework.common.pojo.PageResult;
import com.hlkj.framework.common.util.collection.CollectionUtils;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.hlkj.framework.mybatis.core.utils.MyBatisUtils;
import com.hlkj.pay.common.constants.AdminUserConstant;
import com.hlkj.pay.dto.admin.RoleDto;
import com.hlkj.pay.dto.admin.RoleQueryDto;
import com.hlkj.pay.infrastructure.mapper.admin.RoleMapper;
import com.hlkj.pay.infrastructure.mapper.admin.RolePermissionMapper;
import com.hlkj.pay.infrastructure.model.admin.PermissionDO;
import com.hlkj.pay.infrastructure.model.admin.RoleDO;
import com.hlkj.pay.infrastructure.model.admin.RolePermissionMappingDO;
import com.hlkj.pay.service.CommonSnFilterService;
import com.hlkj.pay.service.admin.IRoleService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/09/01 15:14
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class RoleServiceImpl extends CommonSnFilterService implements IRoleService {

    private final RoleMapper roleMapper;

    private final RolePermissionMapper rolePermissionMapper;

    @Override
    public PageResult<RoleDO> queryRolePage(RoleQueryDto roleQueryDto) {
        return queryPage(roleQueryDto);
    }

    @Override
    public RoleDto queryRoleDetail(String roleCode) {
        return roleDetail(roleCode);

    }

    @Override
    public String addRole(RoleDO roleDO) {
        RoleDO selectOne = selectLatestOne();
        Long code = AdminUserConstant.DEFALUT_ROLE_ID;
        if (selectOne != null) {
            code = selectOne.getId();
        }
        String format = String.format("%07d", code + 1);
        roleDO.setCode(AdminUserConstant.DEFALUT_ROLE_CODEPRE + format);
        roleMapper.insert(roleDO);
        return roleDO.getCode();

    }

    @Override
    public void updateRole(RoleDO roleDO) {
        roleMapper.updateById(roleDO);
    }

    @Override
    public void delRole(String roleCode) {
        RoleQueryDto roleQueryDto = new RoleQueryDto();
        roleQueryDto.setCode(roleCode);
        roleMapper.delete(buildWrapper(roleQueryDto));
    }

    @Override
    public void updateRolePermission(String roleCode, List<PermissionDO> rolePermissionsAfter) {
        StopWatch stopWatch = new StopWatch("updateRolePermission");
        stopWatch.start("selectRolePermissionList");
        // 先查角色对应的权限信息
        RoleQueryDto roleQueryDto = new RoleQueryDto();
        roleQueryDto.setCode(roleCode);
        List<RolePermissionMappingDO> permissionMappingList = selectRolePermissionList(roleQueryDto);
        stopWatch.stop();
        if (CollectionUtils.isEmpty(permissionMappingList)) {
            permissionMappingList = Collections.emptyList();
        }
        stopWatch.start("addRolePermissionMappingList");

        // 之前的code
        List<String> permissionCodesBefore = permissionMappingList.stream().map(RolePermissionMappingDO::getPermissionCode).collect(Collectors.toList());

        Map<String, PermissionDO> rolePermissionAfterMap = rolePermissionsAfter.stream().collect(Collectors.toMap(PermissionDO::getCode, Function.identity(), (t1, t2) -> t2));
        // 提交的code
        Set<String> permissionCodesAfter = rolePermissionAfterMap.keySet();

        // 之后有 之前没有 即新增的code
        List<String> addCodes = CollectionUtils.subtractToList(permissionCodesAfter, permissionCodesBefore);
        // 之后没有 之前有 即删除的code
        List<String> delCodes = CollectionUtils.subtractToList(permissionCodesBefore, permissionCodesAfter);

        // 共同的code 即没有变更的code 需要判断数据权限是否变更
        List<String> noChangeCodes = CollectionUtils.intersection(permissionCodesAfter, permissionCodesBefore).stream().collect(Collectors.toList());

        if (log.isDebugEnabled()) {
            log.debug("updateRolePermission addCodes:{},delCodes:{}", JsonUtils.toJsonString(addCodes), JsonUtils.toJsonString(delCodes));
        }
        stopWatch.stop();
        stopWatch.start("addCodes");
        // 新增的列表
        List<RolePermissionMappingDO> addRolePermissionMappingList = new ArrayList<>(addCodes.size() * 3 / 2);
        addCodes.stream().forEach(addCode -> {
            RolePermissionMappingDO rolePermissionMapping = new RolePermissionMappingDO();
            rolePermissionMapping.setRoleCode(roleCode);
            rolePermissionMapping.setPermissionCode(addCode);
            addRolePermissionMappingList.add(rolePermissionMapping);
        });
        stopWatch.stop();
        stopWatch.start("batchUpdateRolePermission");
        batchUpdateRolePermission(roleCode, delCodes, addRolePermissionMappingList);
        stopWatch.stop();
        if (log.isDebugEnabled()) {
            log.debug("updateRolePermission total:{},updateRolePermission:{}", stopWatch.getTotalTimeMillis(), stopWatch.prettyPrint());
        }
    }

    public void batchUpdateRolePermission(String code, List<String> delPermissionCodes, List<RolePermissionMappingDO> addRolePermissionMappingList) {
        if (CollectionUtils.isNotEmpty(addRolePermissionMappingList)) {
            // 新增
            rolePermissionMapper.insertBatch(addRolePermissionMappingList);
        }
        if (CollectionUtils.isNotEmpty(delPermissionCodes)) {
            RoleQueryDto roleQueryDto = new RoleQueryDto();
            roleQueryDto.setPermissionCodeList(delPermissionCodes);
            roleQueryDto.setCode(code);
            // 删除
            rolePermissionMapper.delete(buildPermissionWrapper(roleQueryDto));
        }
    }

    @Override
    public List<RoleDO> queryRoleList(RoleQueryDto roleQueryDto) {
        LambdaQueryWrapper<RoleDO> queryWrapper = buildWrapper(roleQueryDto);
        return roleMapper.selectRoleList(roleQueryDto.getSn(), roleQueryDto.getSnList(),queryWrapper);
    }

    @Override
    public RoleDto queryRoleDto(String roleCode) {
        return roleDetail(roleCode);
    }

    @Override
    public RoleDO queryRoleByName(String roleName) {
        RoleQueryDto roleQueryDto = new RoleQueryDto();
        roleQueryDto.setName(roleName);
        return selectOne(roleQueryDto);
    }

    @Override
    public List<RolePermissionMappingDO> queryPermissionCodeByRoleCode(List<String> roleCodes) {
        return queryRolePermission(roleCodes);
    }

    @Override
    public List<RolePermissionMappingDO> queryPermissionCodeByPermissionCode(String permissionCode) {
        RoleQueryDto roleQueryDto = new RoleQueryDto();
        roleQueryDto.setPermissionCode(permissionCode);
        return selectRolePermissionList(roleQueryDto);
    }

    public List<RolePermissionMappingDO> queryRolePermission(List<String> roleCodes) {
        RoleQueryDto roleQueryDto = new RoleQueryDto();
        roleQueryDto.setCodeList(roleCodes);
        return selectRolePermissionList(roleQueryDto);
    }

    public PageResult<RoleDO> queryPage(RoleQueryDto roleQueryDto) {
        LambdaQueryWrapper<RoleDO> queryWrapper = buildWrapper(roleQueryDto);
        IPage<RoleDO> mpPage = MyBatisUtils.buildPage(roleQueryDto);
        roleMapper.selectRolePage(mpPage, roleQueryDto.getSn(),roleQueryDto.getSnList(), queryWrapper);
        return new PageResult(mpPage.getRecords(), mpPage.getTotal(), mpPage.getCurrent(), mpPage.getSize(), mpPage.getPages());
    }

    RoleDO selectOne(RoleQueryDto tenantQueryDO) {
        LambdaQueryWrapper<RoleDO> wrapper = buildWrapper(tenantQueryDO);
        wrapper.orderByDesc(RoleDO::getCreateTime);
        wrapper.last(" limit 1");
        return roleMapper.selectOne(wrapper);
    }

    RoleDO selectLatestOne() {
        return roleMapper.selectLatestOne();
    }

    public RoleDto roleDetail(String roleCode) {
        RoleQueryDto roleQueryDto = new RoleQueryDto();
        roleQueryDto.setCode(roleCode);
        RoleDO roleDO = selectOne(roleQueryDto);
        if (roleDO == null) {
            return null;
        }
        RoleDto roleDto = new RoleDto();
        BeanUtils.copyProperties(roleDO, roleDto);
        if (roleDO.getSuperAdminFlag() != null && roleDO.getSuperAdminFlag()) {
            return roleDto;
        }
        List<RolePermissionMappingDO> permissionMappingList = selectRolePermissionList(roleQueryDto);
        if (CollectionUtils.isEmpty(permissionMappingList)) {
            permissionMappingList = Collections.emptyList();
        }
        roleDto.setRolePermissions(permissionMappingList);
        return roleDto;
    }

    /**
     * 权限关系列表查询
     * 
     * @param tenantQueryDO
     * @return
     */
    List<RolePermissionMappingDO> selectRolePermissionList(RoleQueryDto tenantQueryDO) {
        LambdaQueryWrapper<RolePermissionMappingDO> buildPermissionWrapper = buildPermissionWrapper(tenantQueryDO);
        return rolePermissionMapper.selectList(buildPermissionWrapper);
    }

    /**
     * 查询条件封装
     * 
     * @param roleQueryDto
     * @return
     */
    LambdaQueryWrapper<RoleDO> buildWrapper(RoleQueryDto roleQueryDto) {
        filterSn(roleQueryDto);
        LambdaQueryWrapperX<RoleDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.likeIfPresent(RoleDO::getName, roleQueryDto.getLikeName());
        queryWrapper.eqIfPresent(RoleDO::getName, roleQueryDto.getName());
        queryWrapper.inIfPresent(RoleDO::getCode, roleQueryDto.getCodeList());
        queryWrapper.notInIfPresent(RoleDO::getCode, roleQueryDto.getFilterCodeList());
        queryWrapper.eqIfPresent(RoleDO::getCode, roleQueryDto.getCode());
        queryWrapper.eqIfPresent(RoleDO::getSysType, roleQueryDto.getSysType());
        // queryWrapper.eqIfPresent(RoleDO::getSn, roleQueryDto.getSn());
        // queryWrapper.inIfPresent(RoleDO::getSn, roleQueryDto.getSnList());
        queryWrapper.eqIfPresent(RoleDO::getSuperAdminFlag, roleQueryDto.getSuperAdminFlag());
        queryWrapper.eqIfPresent(RoleDO::getDefaultRole, roleQueryDto.getDefaultRole());
        queryWrapper.eqIfPresent(RoleDO::getDeleteFlag, 0);

        return queryWrapper;
    }

    /**
     * 查询条件封装
     * 
     * @param roleQueryDto
     * @return
     */
    LambdaQueryWrapper<RolePermissionMappingDO> buildPermissionWrapper(RoleQueryDto roleQueryDto) {
        LambdaQueryWrapperX<RolePermissionMappingDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.inIfPresent(RolePermissionMappingDO::getRoleCode, roleQueryDto.getCodeList());
        queryWrapper.eqIfPresent(RolePermissionMappingDO::getRoleCode, roleQueryDto.getCode());
        queryWrapper.inIfPresent(RolePermissionMappingDO::getPermissionCode, roleQueryDto.getPermissionCodeList());
        queryWrapper.eqIfPresent(RolePermissionMappingDO::getPermissionCode, roleQueryDto.getPermissionCode());

        return queryWrapper;
    }
}
